package com.kwdb.server;

import com.kwdb.server.service.KWDBServiceImpl;
import com.kwdb.server.storage.StorageEngine;
import com.kwdb.server.storage.RocksDBStorageEngine;
import com.kwdb.server.storage.KWDBStorageEngine;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

/**
 * KWDB服务器主类 - 基于gRPC的高性能服务器
 */
public class KWDBServer {
    
    private static final Logger logger = LoggerFactory.getLogger(KWDBServer.class);
    
    private final int port;
    private final Server server;
    private final StorageEngine storageEngine;
    
    /**
     * 构造函数 - 使用默认配置（RocksDB）
     */
    public KWDBServer(int port) throws IOException {
        this(port, new Properties());
    }
    
    /**
     * 构造函数 - 使用配置文件
     */
    public KWDBServer(int port, Properties config) throws IOException {
        this.port = port;
        
        // 根据配置选择存储引擎
        String databaseType = config.getProperty("database.type", "mock");
        String kwdbHost = config.getProperty("kwdb.host", "none");
        
        logger.info("初始化存储引擎，类型: {}, 主机: {}", databaseType, kwdbHost);
        
        if ("kwdb".equalsIgnoreCase(databaseType) && 
            kwdbHost != null && !kwdbHost.isEmpty() && !"none".equalsIgnoreCase(kwdbHost)) {
            // 使用 KWDB 数据库
            int kwdbPort = Integer.parseInt(config.getProperty("kwdb.port", "26257"));
            String kwdbDatabase = config.getProperty("kwdb.database", "kwdb");
            String kwdbUsername = config.getProperty("kwdb.username", "root");
            String kwdbPassword = config.getProperty("kwdb.password", "");
            
            logger.info("连接到 KWDB 数据库: {}:{}/{}", kwdbHost, kwdbPort, kwdbDatabase);
            this.storageEngine = new KWDBStorageEngine(
                kwdbHost, kwdbPort, kwdbDatabase, kwdbUsername, kwdbPassword
            );
        } else {
            // 使用 RocksDB（模拟模式）
            logger.info("使用 RocksDB 模拟存储");
            this.storageEngine = new RocksDBStorageEngine();
        }
        
        // 构建 gRPC 服务器
        this.server = NettyServerBuilder.forPort(port)
                .addService(new KWDBServiceImpl(storageEngine))
                .maxInboundMessageSize(4 * 1024 * 1024) // 4MB
                .maxInboundMetadataSize(8 * 1024) // 8KB
                .keepAliveTime(30, TimeUnit.SECONDS)
                .keepAliveTimeout(5, TimeUnit.SECONDS)
                .permitKeepAliveWithoutCalls(true)
                .permitKeepAliveTime(30, TimeUnit.SECONDS)
                .build();
    }
    
    /**
     * 启动服务器
     * @throws IOException 启动异常
     */
    public void start() throws IOException {
        server.start();
        logger.info("KWDB服务器启动成功，端口: {}", port);
        
        // 添加关闭钩子
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            logger.info("正在关闭KWDB服务器...");
            try {
                KWDBServer.this.stop();
            } catch (InterruptedException e) {
                logger.error("服务器关闭被中断", e);
                Thread.currentThread().interrupt();
            }
        }));
    }
    
    /**
     * 停止服务器
     * @throws InterruptedException 中断异常
     */
    public void stop() throws InterruptedException {
        if (server != null) {
            server.shutdown();
            if (!server.awaitTermination(30, TimeUnit.SECONDS)) {
                server.shutdownNow();
                if (!server.awaitTermination(5, TimeUnit.SECONDS)) {
                    logger.error("服务器未能正常关闭");
                }
            }
        }
        
        // 关闭存储引擎
        if (storageEngine != null) {
            storageEngine.shutdown();
        }
        
        logger.info("KWDB服务器已关闭");
    }
    
    /**
     * 等待服务器终止
     * @throws InterruptedException 中断异常
     */
    public void blockUntilShutdown() throws InterruptedException {
        if (server != null) {
            server.awaitTermination();
        }
    }
    
    /**
     * 主方法
     * @param args 命令行参数
     * @throws IOException IO异常
     * @throws InterruptedException 中断异常
     */
    public static void main(String[] args) throws IOException, InterruptedException {
        // 加载配置文件
        Properties config = loadConfiguration();
        
        // 从配置文件读取端口
        int port = Integer.parseInt(config.getProperty("server.port", "9090"));
        
        // 解析命令行参数（命令行参数优先级更高）
        String configFile = null;
        for (int i = 0; i < args.length; i++) {
            if ("--port".equals(args[i]) && i + 1 < args.length) {
                port = Integer.parseInt(args[i + 1]);
                i++;
            } else if ("--config".equals(args[i]) && i + 1 < args.length) {
                configFile = args[i + 1];
                i++;
            }
        }
        
        // 如果指定了配置文件，重新加载
        if (configFile != null) {
            config = loadConfiguration(configFile);
            port = Integer.parseInt(config.getProperty("server.port", String.valueOf(port)));
        }
        
        // 打印配置信息
        logger.info("==========================================");
        logger.info("KWDB Server 启动配置:");
        logger.info("  端口: {}", port);
        logger.info("  数据库类型: {}", config.getProperty("database.type", "mock"));
        logger.info("  KWDB 主机: {}", config.getProperty("kwdb.host", "none"));
        logger.info("  KWDB 端口: {}", config.getProperty("kwdb.port", "26257"));
        logger.info("  KWDB 数据库: {}", config.getProperty("kwdb.database", "kwdb"));
        logger.info("==========================================");
        
        KWDBServer server = new KWDBServer(port, config);
        server.start();
        server.blockUntilShutdown();
    }
    
    /**
     * 加载配置文件（从 classpath）
     */
    private static Properties loadConfiguration() {
        Properties config = new Properties();
        
        try (InputStream input = KWDBServer.class.getClassLoader()
                .getResourceAsStream("application.properties")) {
            if (input != null) {
                config.load(input);
                logger.info("已加载配置文件: application.properties");
            } else {
                logger.warn("未找到配置文件 application.properties，使用默认配置");
            }
        } catch (IOException e) {
            logger.error("加载配置文件失败", e);
        }
        
        return config;
    }
    
    /**
     * 加载配置文件（从文件路径）
     */
    private static Properties loadConfiguration(String filePath) {
        Properties config = new Properties();
        
        try (InputStream input = new FileInputStream(filePath)) {
            config.load(input);
            logger.info("已加载配置文件: {}", filePath);
        } catch (IOException e) {
            logger.error("加载配置文件失败: {}", filePath, e);
            logger.warn("使用默认配置");
        }
        
        return config;
    }
}
